from demos import *
from pist import PistonCluster

width = 40



def clear_stdin():
    """Clear any pending input from the standard input buffer.

    This function ensures that no stale or unintended data remains in stdin
    before reading user input interactively. On Windows, it uses the msvcrt
    module to discard characters from the input buffer. On POSIX-compliant
    systems (e.g., Linux, macOS...), it either discards the data by reading 
    or flushes it using termios.tcflush if stdin is a terminal.
    """

    """
    Function Author: James Cherti
    License: MIT
    URL: https://www.jamescherti.com/python-flushing-stdin-before-using-input-function/
    """
    
    try:
        if os.name == "nt":
            import msvcrt  # pylint: disable=import-outside-toplevel

            # For Windows systems, Check if there is any pending input in the
            # buffer Discard characters one at a time until the buffer is empty.
            while msvcrt.kbhit():
                msvcrt.getch()
        elif os.name == "posix":

            if sys.stdin:
                if sys.stdin.isatty():
                    # pylint: disable=import-outside-toplevel
                    from termios import TCIFLUSH, tcflush
                    # Flush the input buffer
                    tcflush(sys.stdin.fileno(), TCIFLUSH)
                else:
                    # Read and discard input (in chunks).
                    while sys.stdin.read(1024):
                        pass
    except ImportError:
        pass

def main():
    print(("=" * width))
    print("Minecraft Piston's".center(width))
    print("Extender & Substructer".center(width))
    print("Emulator".center(width))
    print(("=" * width) + '\n')

    pstG = PistonCluster().set(1)
    while True:
        try:
            clear_stdin()
            asw = input(">").split()
            cmd = asw[0]
        except IndexError:
            print("e (emu) Emulate a built in demo")

            print("s  (set) init pistons.")
            print("p  (print) print pistons' states.")
            print("t  (triger) triger piston at specific pos.")
            print("tp (trig-and-print) triger piston at specific pos, then print.")

            print("o  (toggle) triger piston at specific pos.")

            print("q (quit) quit the program.")
        else:
            if cmd == 'e' or cmd == "emu":
                try:
                    case = asw[1]
                    parm = int(asw[2])
                    if case not in ["chs","bst","bstbk","glph"]:
                        raise IndexError

                except IndexError:
                    print("command 'emu':")
                    print("'emu bst [NumberOfPiston] for fastest solution.")
                    print("'emu chs [NumberOfPiston] for chaos theory solution.")
                else:
                    try:
                        eval("{}_demo({})".format(case,",".join([str(k) for k in asw[2:]])))
                    except KeyboardInterrupt:
                        print("interrupted.")
                        pass

            elif cmd == 's' or cmd == "set":
                try:
                    parm = int(asw[1])
                    if parm <= 0:
                        raise IndexError
                except IndexError or ValueError:
                    print("command 'set':")
                    print("'set [NumberOfPiston]'")
                else:
                    pstG.set(parm)

            elif cmd == 'p' or cmd == "print":
                print(pstG.getState())

            elif cmd == 't' or cmd == "triger":
                try:
                    parm = int(asw[1])
                    if parm not in pstG.getValidRange():
                        raise IndexError
                except IndexError or ValueError:
                    print("command 'triger':")
                    print("'triger [piston idx]'")
                else:
                    pstG.trig(parm)

            elif cmd == 'o' or cmd == "toggle":
                try:
                    parm = int(asw[1])
                    if parm not in pstG.getValidRange():
                        raise IndexError
                except IndexError or ValueError:
                    print("command 'toggle':")
                    print("'toggle [piston idx]'")
                else:
                    pstG.toggle(parm)

            elif cmd == 'tp':
                try:
                    parm = int(asw[1])
                    if parm not in pstG.getValidRange():
                        raise IndexError
                except IndexError or ValueError:
                    print("command 'trigger':")
                    print("'trigger print [piston idx]'")
                else:
                    pstG.trig(int(asw[1]))
                    print(pstG.getState())

            elif cmd == 'q' or cmd == "quit":
                return

            else:
                print("Unknown Command '{}'.".format(cmd))


if __name__ == "__main__":
    main()
